#ifndef __M_BINDING_H__
#define __M_BINDING_H__
#include "../mqCommon/logger.hpp"
#include "../mqCommon/helper.hpp"
#include "../mqCommon/mq_msg.pb.h"
#include <iostream>
#include <memory>
#include <mutex>
#include <unordered_map>

namespace yqx{
    //绑定类
    struct Binding{
        using ptr = std::shared_ptr<Binding>;
        std::string _exchange_name;
        std::string _msgqueue_name;
        std::string _binding_key;

        Binding(const std::string& ename, const std::string& qname, const std::string& binding_key)
        :_exchange_name(ename), _msgqueue_name(qname), _binding_key(binding_key){}
    };

    /*
        交换机和绑定是一对多的关系，消息队列和绑定是一对一的关系。
        所以用MsgQueueBindingMap来存消息队列和绑定的映射，再用BindingMap存交换机和它所有的消息队列的映射关系。
    */
    using MsgQueueBindingMap = std::unordered_map<std::string, Binding::ptr>;//可以通过队列名找到绑定信息
    using BindingMap = std::unordered_map<std::string, MsgQueueBindingMap>;//可以通过交换机名找到它所有的绑定信息
    //绑定数据持久化类
    class BindingMapper{
        public:
            BindingMapper(const std::string& dbfile):_sh(dbfile){
                std::string parentPath = FileHelper::getParentDirectory(dbfile);
                FileHelper::createDirectory(parentPath);
                assert(_sh.open());
                createTable();
            }
            //创建表
            void createTable(){
                #define CREATE_BINDING_TABLE "create table if not exists binding_table(exchange_name varchar(32), msgqueue_name varchar(32), binding_key varchar(128));"
                bool ret = _sh.exec(CREATE_BINDING_TABLE, nullptr, nullptr);
                if(ret == false){
                    LOG("创建绑定数据库表失败！");
                    abort();
                }
            }
            //删除表
            void removeTable(){
                #define DROP_BINDING_TABLE "drop table if exists binding_table;"
                bool ret = _sh.exec(DROP_BINDING_TABLE, nullptr, nullptr);
                if(ret == false){
                    LOG("删除消息队列数据库表失败！");
                    abort();
                }
            }
            //向表里写入一个绑定关系
            bool insert(Binding::ptr& bp){
                std::stringstream ss;
                ss << "insert into binding_table values(";
                ss << "'" << bp->_exchange_name << "', ";
                ss << "'" << bp->_msgqueue_name << "', ";
                ss << "'" << bp->_binding_key << "');";
                return _sh.exec(ss.str(), nullptr, nullptr);
            }
            //删除表里一个绑定关系
            bool remove(const std::string& ename, const std::string& qname){
                std::stringstream ss;
                ss << "delete from binding_table where ";
                ss << "exchange_name='" << ename << "' and ";
                ss << "msgqueue_name='" << qname << "';";
                return _sh.exec(ss.str(), nullptr, nullptr);
            }
            //删除表里和这个交换机相关的全部绑定关系
            void removeExchangeBindings(const std::string& ename){
                std::stringstream ss;
                ss << "delete from binding_table where ";
                ss << "exchange_name='" << ename << "';";
                _sh.exec(ss.str(), nullptr, nullptr);
            }
            //删除表里和这个消息队列相关的全部绑定关系
            void removeMsgQueueBindings(const std::string& qname){
                std::stringstream ss;
                ss << "delete from binding_table where ";
                ss << "msgqueue_name='" << qname << "';";
                _sh.exec(ss.str(), nullptr, nullptr);
            }
            //恢复数据用
            BindingMap recovery(){
                BindingMap res;
                std::string ss = "select exchange_name, msgqueue_name, binding_key from binding_table;";
                _sh.exec(ss, selectCallback, &res);
                return res;
            }
        private:
            static int selectCallback(void* arg, int numcol, char** row, char** fields){
                BindingMap* res = (BindingMap*)arg;
                Binding::ptr bp = std::make_shared<Binding>(row[0], row[1], row[2]);
                MsgQueueBindingMap& qmap = (*res)[bp->_exchange_name];
                qmap.insert(std::make_pair(bp->_msgqueue_name, bp));
                return 0;
            }

        private:
            SqliteHelper _sh;
    };
    //绑定数据管理类
    class BindingManager{
        public:
            using ptr = std::shared_ptr<BindingManager>;
            BindingManager(const std::string& dbfile):_mapper(dbfile){
                _bindings = _mapper.recovery();
            }
            //建立一个绑定关系
            bool bind(const std::string& ename, const std::string& qname, const std::string& binding_key, bool durable){
                std::unique_lock<std::mutex> lock(_mtx);
                auto it = _bindings.find(ename);
                if(it != _bindings.end() && it->second.find(qname) != it->second.end())
                    return true;
                Binding::ptr bp = std::make_shared<Binding>(ename, qname, binding_key);
                auto& qbmap = _bindings[ename];
                qbmap.insert(std::make_pair(qname, bp));
                //绑定关系是否持久化取决于交换机和消息队列是否持久化，为了解耦和，就直接从外界传durable来判断是否持久化这个binding
                if(durable){
                    int res = _mapper.insert(bp);
                    if(res == false)
                        return false;
                }
                return true;
            }
            //解绑
            void unbind(const std::string& ename, const std::string& qname){
                std::unique_lock<std::mutex> lock(_mtx);
                auto eit = _bindings.find(ename);
                if(eit == _bindings.end())
                    return;
                auto qit = eit->second.find(qname);
                if(qit == eit->second.end())
                    return;
                _mapper.remove(ename, qname);
                _bindings[ename].erase(qname);

            }
            //删除该交换机的所有绑定信息
            void removeExchangeBindings(const std::string& ename){
                std::unique_lock<std::mutex> lock(_mtx);
                _mapper.removeExchangeBindings(ename);
                _bindings.erase(ename);
            }
            //删除该消息队列的所有绑定信息
            void removeMsgQueueBindings(const std::string& qname){
                std::unique_lock<std::mutex> lock(_mtx);
                _mapper.removeMsgQueueBindings(qname);
                for(auto it = _bindings.begin(); it != _bindings.end(); ++it){
                    if(it->second.find(qname) != it->second.end())
                        it->second.erase(qname);
                }
            }
            //获取一个交换机的所有绑定信息
            MsgQueueBindingMap getExchangeBindings(const std::string& ename){
                std::unique_lock<std::mutex> lock(_mtx);
                auto it = _bindings.find(ename);
                if(it == _bindings.end())
                    return MsgQueueBindingMap();
                return it->second;
            }
            //获取一个指定的绑定关系
            Binding::ptr getBinding(const std::string& ename, const std::string& qname){
                std::unique_lock<std::mutex> lock(_mtx);
                auto eit = _bindings.find(ename);
                if(eit == _bindings.end())
                    return nullptr;
                auto qit = eit->second.find(qname);
                if(qit == eit->second.end())
                    return nullptr;
                return qit->second;
            }
            //判断绑定关系是否存在
            bool exists(const std::string& ename, const std::string& qname){
                std::unique_lock<std::mutex> lock(_mtx);
                auto eit = _bindings.find(ename);
                if(eit == _bindings.end())
                    return false;
                auto qit = eit->second.find(qname);
                if(qit == eit->second.end())
                    return false;
                return true;
            }
            void clear(){
                std::unique_lock<std::mutex> lock(_mtx);
                _mapper.removeTable();
                _bindings.clear();
            }

        private:
            std::mutex _mtx;
            BindingMapper _mapper;
            BindingMap _bindings;
    }; 
}
#endif